<?php

namespace App\CustHub\Service;

use App\Common\Constants\PayMethodConstants;
use App\Common\Constants\PayWayConstants;
use App\Common\Dto\PaymentDto;
use App\Common\Helpers\UrlHelper;
use App\Common\Interfaces\PaymentInterface;
use App\CustHub\Constants\UserMoneyLogTypeConstants;
use App\CustHub\Helpers\BcMath;
use App\CustHub\Mapper\ChOrderMapper;
use App\CustHub\Vo\UserBalanceVo;
use App\Robot\Dto\CommonJobDto;
use App\Robot\Job\CommonJob;
use App\Setting\Service\SettingConfigService;
use Carbon\Carbon;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Mine\Abstracts\AbstractService;
use Mine\Exception\NormalStatusException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class RechargeService extends AbstractService
{
    #[Inject]
    protected ChOrderMapper $orderMapper;

    #[Inject]
    public PaymentInterface $paymentService;


    /**
     * 创建充值订单
     * @param array $data
     * @return string
     */
    public function createOrder(array $data): string
    {
        $money = $data['money'];
        $serviceFee = $this->getServiceFee($money);
        $dzMoney = BcMath::sub($money,$serviceFee);
        $orderData = [
            'uid' => $data['main_uid'],
            'order_no' => generateOrderNumber(),
            'total_amount' => $data['money'],
            'pay_amount' => $data['money'],
            'remark' => '在线充值余额，服务费' . $serviceFee.'元，实际到账' . $dzMoney.'元',
            'ext' => $dzMoney
        ];
        $orderId = $this->orderMapper->save($orderData);
        if(!$orderId){
            throw new NormalStatusException('充值订单创建失败，请重试');
        }

        container()->get(LowQueueService::class)->push(new CommonJob(new CommonJobDto(
            classname: RechargeService::class,
            method: 'payTimeout',
            data:[
                'order_no' => $orderData['order_no']
            ]
        )),30 * 60);

        return $orderData['order_no'];
    }

    private function getServiceFee($money)
    {
        $rechargeFeeRatio = container()->get(SettingConfigService::class)->getConfigByKey('recharge_fee_ratio')['value'] ?? 0;

        $rechargeFee = BcMath::round($money * $rechargeFeeRatio / 1000,2);
        return $rechargeFee;
    }

    /**
     * 支付
     * @param array $data
     */
    public function pay(array $data)
    {
        $payWay = $data['pay_way'];

        $orderInfo = $this->orderMapper->findByOrderNo($data['order_no']);
        if(empty($orderInfo)){
            throw new NormalStatusException('订单不存在');
        }
        $orderInfo->pay_way = $data['pay_way'];
        $orderInfo->save();

        $payment = new PaymentDto();
        $payment->setOrderNo($orderInfo->order_no);
        $payment->setPayAmount($orderInfo->pay_amount);
        $payment->setPayWay($data['pay_way']);
        $payment->setSubject($orderInfo->remark);

        $systemConfig = container()->get(SettingConfigService::class);
        $domain = $systemConfig->getConfigByKey('ch_api_url')['value'];

        $url = 'pay/notify/rechargeNotify';
        if($payWay == PayWayConstants::WECHAT){
            $notifyUrl = $domain.'/'.$url;
        }else{
            $payment->setPayMethod(PayMethodConstants::SCAN);
            $notifyUrl = UrlHelper::url($url,['pay_way'=>$payWay],$domain);
        }

        $payment->setNotifyUrl($notifyUrl);

        return $this->paymentService->unifiedPay($payment);
    }

    /**
     * 订单支付状态查询
     * @param array $data
     * @return int
     */
    public function checkPayStatus(array $data): int
    {
        $orderInfo = $this->orderMapper->model::query()
            ->where('uid',$data['main_uid'])
            ->where('order_no',$data['order_no'])
            ->first();
        if(empty($orderInfo)){
            throw new NormalStatusException('订单不存在');
        }
        return $orderInfo['status'];
    }

    /**
     * 订单超时取消
     * @param array $data
     * @return void
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function payTimeout(array $data): void
    {
        $orderNo = $data['order_no'];
        $orderInfo = $this->orderMapper->findByOrderNo($orderNo);
        if(empty($orderInfo) || $orderInfo->status != 0){
            return;
        }
        $orderInfo->status = 2;
        $orderInfo->save();
        logger()->info('充值订单超时取消成功',$data);
    }


    /**
     * 在线充值回调
     * @param string $orderNo
     * @param string $transactionId
     * @param array $ext
     * @return bool
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function rechargeNotify(string $orderNo, string $transactionId,array $ext = []): bool
    {
        $orderInfo = $this->orderMapper->findByOrderNo($orderNo);
        if(empty($orderInfo)){
            return true;
        }

        if($orderInfo->status != 0){
            return true;
        }

        Db::beginTransaction();
        try {
            $orderInfo->status = 1;
            $orderInfo->transaction_id = $transactionId;
            $orderInfo->pay_time = Carbon::now()->toDateTimeString();
            $result = $orderInfo->save();
            if(!$result){
                throw new NormalStatusException("订单编号:{$orderNo}_状态更新失败");
            }

            $result = container()->get(UserBalanceService::class)->updateBalance(new UserBalanceVo(
                uid: $orderInfo->uid,
                money: (float)$orderInfo->ext,
                businessType: UserMoneyLogTypeConstants::RECHARGE,
                order_id: $orderInfo->id,
                remark: '在线充值余额'
            ));

            if(!$result){
                throw new NormalStatusException("订单编号:{$orderNo}_余额变动失败");
            }
            Db::commit();
            return true;
        }catch (\Throwable $e){
            Db::rollBack();
            logger()->info('在线充值失败'.$e->getMessage());
            return false;
        }
    }
}